#ifndef UDPNET_H_
#define UDPNET_H_
/*********************************************************/
#include <Poco/Thread.h>
#include <Poco/Runnable.h>
#include <Poco/Net/DatagramSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Mutex.h>
#include <string>
#include <queue>

#define UDP_PACKET_SIZE_LIMIT 65507		// Theoretical limit of the udp packet size
/*********************************************************/
struct Message {
	Poco::Net::SocketAddress	addr;
	std::string			msg;
};
/*********************************************************/
/** Provides an easy to use, multithreaded interface to send & receive datagram packets **/
class UDPNet : public Poco::Runnable
{
private:
	// Variables
	Poco::Net::SocketAddress 	localAddr;		// Local address
	Poco::Net::SocketAddress 	targetAddr;		// Target to send replies to
	Poco::Net::DatagramSocket 	sock;			// UDP Socket
	std::queue<Message>		data;			// Data received from the socket
	Poco::Thread			lThread;		// local thread handle
	std::string			eventStr;		// Event string 
	mutable Poco::Mutex		mutex;			// Mutual exclusion object
	bool				halt;			// Is the server needed to halt?

	// Methods
	void run();						// Thread entry point
	
protected:
	// Methods
	UDPNet(const UDPNet&) {};				// Copy Construction is forbidden
public:

	// Methods for network messaging
	void send(const std::string& msg);			// Sends data
	void sendTo(const std::string&, const std::string&);	// Sends data to a particular socket ( doesn't affect the response address! )
	bool available() const;					// Returns true if data is available, false if not
	std::string pop();					// Returns the element at the front of the queue and deletes it
	std::string pop(Poco::Net::SocketAddress&);		// Returns the element at the front of the queue together with the address it was received from

	// Management methods
	void setLocalAddress(const std::string& host, const int port);		// Set the local address 
	void setResponseAddress(const std::string& host, const int port);	// Send to this address
	void getLocalAddress(std::string& host, int& port);			// get the local address 
	void getResponseAddress(std::string& host, int& port);			// get the address to send to
	void start(const std::string&);						// Starts the udp network
	void stop();								// stops the udp network

	// Misc methods
	static unsigned int getAvailablePort(const std::string&, const unsigned int, const unsigned int);// Returns an available port

	// Construction & Destruction
	UDPNet(const std::string&, const int);					// Bind the local socket to a host & port
	~UDPNet();
};
/*********************************************************/
#endif //UDPNET_H_
